package com.geeguo.ebuilder.client.business.system.excelimport.service.impl;

import com.geeguo.ebuilder.client.base.core.dictionary.ExcelImportStatusEnum;
import com.geeguo.ebuilder.client.base.core.dictionary.ExcelImportTypeEnum;
import com.geeguo.ebuilder.client.base.tenant.model.DataContext;
import com.geeguo.ebuilder.client.business.system.excelimport.model.ExcelImportVO;
import com.geeguo.ebuilder.client.business.system.excelimport.service.ExcelImportExecuteService;
import com.geeguo.ebuilder.client.business.system.excelimport.service.ExcelImportService;
import com.geeguo.ebuilder.client.business.system.excelimport.service.ExcelImportTaskService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.*;

@Slf4j
@Service
public class ExcelImportTaskServiceImpl implements ExcelImportTaskService {

    @Autowired
    private ApplicationContext applicationContext;
    @Autowired
    private ExcelImportService excelImportService;

    private Map<String, ExcelImportExecuteService> excelImportServiceMapping;

    private static final ExecutorService threadPoolExecutor = new ThreadPoolExecutor(
            2,
            4,
            60,
            TimeUnit.SECONDS,
            new ArrayBlockingQueue<Runnable>(20),
            Executors.defaultThreadFactory(),
            new ThreadPoolExecutor.AbortPolicy());

    @Override
    public void submitTask(String id, DataContext dataContext) {
        ExcelImportVO excelImport = excelImportService.get(id, dataContext);
        if (excelImport != null) {
            if (ExcelImportStatusEnum.Created.getValue() == excelImport.getStatus()) {
                excelImportService.updatePending(id, dataContext);
                try {
                    ExcelImportTypeEnum typeEnum = ExcelImportTypeEnum.parse(excelImport.getType());
                    if (typeEnum != null) {
                        ExcelImportExecuteService excelImportExecuteService = this.getExcelImportExecuteService(typeEnum);
                        if (excelImportExecuteService != null) {
                            threadPoolExecutor.execute(() -> {
                                if (excelImportService.updateProcessing(id, new Date(), dataContext)) {
                                    try {
                                        ExcelImportVO vo = excelImportService.get(id, dataContext);
                                        if (vo != null) {
                                            excelImportExecuteService.executeImport(vo, dataContext);
                                            excelImportService.updateFinished(id, new Date(), dataContext);
                                        }
                                    } catch (Exception e) {
                                        log.error("执行导入失败!", e);
                                        excelImportService.updateError(id, e.getMessage(), dataContext);
                                    }
                                }
                            });
                        } else {
                            excelImportService.updateError(id, "没有找到Excel文件导入处理方法!", dataContext);
                        }
                    } else {
                        excelImportService.updateError(id, "未知导入类型!", dataContext);
                    }
                } catch (RejectedExecutionException e) {
                    excelImportService.updateError(id, "任务队列已满，请稍后再试!", dataContext);
                }
            }
        }
    }

    private ExcelImportExecuteService getExcelImportExecuteService(ExcelImportTypeEnum typeEnum) {
        if (excelImportServiceMapping == null) {
            excelImportServiceMapping = new HashMap<>();
            Map<String, ExcelImportExecuteService> beanMap = applicationContext.getBeansOfType(ExcelImportExecuteService.class);
            for (ExcelImportExecuteService bean : beanMap.values()) {
                excelImportServiceMapping.put(bean.getExcelImportTypeEnum().getCode(), bean);
            }
        }
        return excelImportServiceMapping.get(typeEnum.getCode());
    }
}
